use crate::components::enums::AppMode;
use crate::util;
use ratatui::{Frame, prelude::*, widgets::*};

use crate::components::component::App;

// ***************************************************************
// ** 渲染键值对列表和输入框的辅助函数 **
// ***************************************************************
pub fn render_kv_list(
    f: &mut Frame,
    app: &App,
    area: Rect,
    mode: AppMode,
    title: Line<'static>,
    input_prompt: &str,
    items: &[String],
) {
    let is_editing = app.mode == mode;
    let block_style = choose_color(is_editing);
    let main_block = Block::default()
        .title(title)
        .borders(Borders::ALL)
        .border_type(BorderType::Rounded)
        .border_style(block_style);

    // 渲染主区块边框，并计算内部可用区域
    let inner_area = main_block.inner(area);
    f.render_widget(main_block, area);

    // 根据是否编辑状态，划分布局（是否预留输入框空间）
    let constraints = if is_editing {
        vec![Constraint::Min(0), Constraint::Length(3)]
    } else {
        vec![Constraint::Min(0)]
    };

    let inner_chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints(constraints)
        .split(inner_area);

    // 渲染键值对列表
    let list_items: Vec<ListItem> = items.iter().map(|i| ListItem::new(i.as_str())).collect();
    let list = List::new(list_items);
    f.render_widget(list, inner_chunks[0]);

    // 编辑模式下渲染输入框和光标
    if is_editing {
        let input_area = inner_chunks[1];
        let input_block = Block::default()
            .title(Span::from(input_prompt))
            .border_style(choose_color(false))
            .borders(Borders::TOP);
        let paragraph = Paragraph::new(app.current_input.as_str()).block(input_block);
        f.render_widget(paragraph, input_area);
        util::set_cursor_position(
            f,
            input_area.x + app.current_input.chars().count() as u16 + 1,
            input_area.y + 1,
        );
    }
}

pub fn create_style_title_default(title: &str, highlight_str_vec: Vec<&str>) -> Line<'static> {
    create_styled_title(title, highlight_str_vec, None, None)
}
/// 创建一个部分文字带样式的 Line，支持高亮多个子串。
///
/// # Arguments
///
/// * `title`: 完整的标题文本。
/// * `highlight_str_vec`: 一个字符串切片vec的向量，包含所有需要高亮的子字符串。
///   如果为空，则默认高亮`title`的第一个字符。
/// * `color`: 高亮颜色。如果为 `None`，默认为 `Color::Yellow`。
/// * `modifier`: 高亮样式。如果为 `None`，默认为 `Modifier::UNDERLINED`。
///
/// # Returns
///
/// * `Line<'static>`: 一个ratatui `Line`，其中指定的部分已被应用样式。
pub fn create_styled_title(
    title: &str,
    highlight_strs: Vec<&str>,
    color: Option<Color>,
    modifier: Option<Modifier>,
) -> Line<'static> {
    // 1. 设置样式
    let hotkey_style = Style::default()
        .fg(color.unwrap_or(Color::Yellow))
        .add_modifier(modifier.unwrap_or(Modifier::UNDERLINED));

    // 2. 决定需要高亮的具体子字符串列表
    let highlights_owned: Vec<String> = if highlight_strs.is_empty() {
        // 如果输入为空，则默认高亮第一个字符
        title
            .chars()
            .next()
            .map(|c| vec![c.to_string()])
            .unwrap_or_default()
    } else {
        highlight_strs.iter().map(|&s| s.to_string()).collect()
    };

    if highlights_owned.is_empty() {
        return Line::from(title.to_string());
    }

    // 3. 查找所有高亮子串在原标题中的位置
    let mut matches: Vec<(usize, usize)> = Vec::new();
    for s in &highlights_owned {
        for (index, _) in title.match_indices(s) {
            matches.push((index, index + s.len()));
        }
    }

    // 按起始位置排序
    matches.sort_by_key(|k| k.0);
    // 去除重复和包含的区间，虽然在简单场景下非必需，但能让逻辑更健壮
    matches.dedup();

    let mut spans = Vec::new();
    let mut last_index = 0;

    // 4. 根据查找到的位置，将原标题分割成普通和高亮两类 Span
    for (start, end) in matches {
        if start > last_index {
            // 添加上一个高亮位置到当前高亮位置之间的普通文本
            spans.push(Span::from(title[last_index..start].to_string()));
        }
        // 添加高亮文本
        spans.push(Span::styled(title[start..end].to_string(), hotkey_style));
        last_index = end;
    }

    // 5. 添加最后一个高亮位置到字符串末尾的普通文本
    if last_index < title.len() {
        spans.push(Span::from(title[last_index..].to_string()));
    }

    Line::from(spans)
}

/// 如果true，返回告警色，否则返回普通色
pub fn choose_color(res: bool) -> Style {
    if res {
        Style::default().fg(Color::Yellow)
    } else {
        Style::default().fg(Color::White)
    }
}
